/**
 * Contains {@link RouteProvider}
 */
package logic;

import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.LinkedList;
import logic.pathelements.PathElement;
import logic.pathelements.Protocol;

/**
 * Paths searcher
 * @author Alexey Akimov <frinatella@gmail.com>
 */
public abstract class RouteProvider {
    
    /**
     * Finds route with minimal cost
     * @param protocol transmission protocol
     * @param srcIp source IPv4
     * @param destIp destination IPv4
     * @param srcPort source port
     * @param destPort destination port
     * @param network workspace
     * @return a route represents by ArrayList of path elements 
     * @throws RouteNotFoundException 
     */
    public ArrayList<PathElement> getRouteByCost(
                    Protocol protocol, Inet4Address srcIp, 
                    Inet4Address destIp, int srcPort, 
                    int destPort, Network network) throws RouteNotFoundException {
        LinkedList<ArrayList<PathElement>> findedPaths = getRoutes(protocol, srcIp, destIp, srcPort, destPort, network);
        int currentMinValue = Integer.MAX_VALUE;
        int value;
        ArrayList<PathElement> currentMinPath = null;
        for (ArrayList<PathElement> path : findedPaths) {
            value = 0;
            for (PathElement pathElement : path) {
                value += pathElement.getCosts();
            }
            if (value < currentMinValue) {
                currentMinValue = value;
                currentMinPath = path;
            }
        }
        return currentMinPath;
    }
    
    /**
     * Finds route with minimal time delay
     * @param protocol transmission protocol
     * @param srcIp source IPv4
     * @param destIp destination IPv4
     * @param srcPort source port
     * @param destPort destination port
     * @param network workspace
     * @return a route represents by ArrayList of path elements 
     * @throws RouteNotFoundException 
     */
    public ArrayList<PathElement> getRouteByDelay(
                    Protocol protocol, Inet4Address srcIp, 
                    Inet4Address destIp, int srcPort, 
                    int destPort, Network network) throws RouteNotFoundException {
        LinkedList<ArrayList<PathElement>> findedPaths = getRoutes(protocol, srcIp, destIp, srcPort, destPort, network);
        int currentMinValue = Integer.MAX_VALUE;
        int value;
        ArrayList<PathElement> currentMinPath = null;
        for (ArrayList<PathElement> path : findedPaths) {
            value = 0;
            for (PathElement pathElement : path) {
                value += pathElement.getTimeDelay();
            }
            if (value < currentMinValue) {
                currentMinValue = value;
                currentMinPath = path;
            }
        }
        return currentMinPath;
    }
    
    /**
     * Finds route with minimal cost
     * @param protocol transmission protocol
     * @param srcIp source IPv4
     * @param destIp destination IPv4
     * @param srcPort source port
     * @param destPort destination port
     * @param network workspace
     * @return a route represents by ArrayList of path elements 
     * @throws RouteNotFoundException 
     */
    public ArrayList<PathElement> getRouteByCost(
                    Protocol protocol, String srcIp, 
                    String destIp, int srcPort, 
                    int destPort, Network network) throws RouteNotFoundException, UnknownHostException {
        return getRouteByCost(protocol, (Inet4Address) Inet4Address.getByName(srcIp), (Inet4Address) Inet4Address.getByName(destIp), srcPort, destPort, network);
    }
    
    /**
     * Finds route with minimal time delay
     * @param protocol transmission protocol
     * @param srcIp source IPv4
     * @param destIp destination IPv4
     * @param srcPort source port
     * @param destPort destination port
     * @param network workspace
     * @return a route represents by ArrayList of path elements 
     * @throws RouteNotFoundException 
     */
    public ArrayList<PathElement> getRouteByDelay(
                    Protocol protocol, String srcIp, 
                    String destIp, int srcPort, 
                    int destPort, Network network) throws RouteNotFoundException, UnknownHostException {
        return getRouteByDelay(protocol, (Inet4Address) Inet4Address.getByName(srcIp), (Inet4Address) Inet4Address.getByName(destIp), srcPort, destPort, network);
    }
    
    /**
     * Finds routes
     * @param protocol transmission protocol
     * @param srcIp source IPv4
     * @param destIp destination IPv4
     * @param srcPort source port
     * @param destPort destination port
     * @param network workspace
     * @return routes represents by LinkedList of paths (ArrayLists) of path elements 
     * @throws RouteNotFoundException 
     */
    public abstract LinkedList<ArrayList<PathElement>> getRoutes(
                    Protocol protocol, Inet4Address srcIp, 
                    Inet4Address destIp, int srcPort, 
                    int destPort, Network network) throws RouteNotFoundException;
    
    /**
     * Finds routes
     * @param protocol transmission protocol
     * @param srcIp source IPv4
     * @param destIp destination IPv4
     * @param srcPort source port
     * @param destPort destination port
     * @param network workspace
     * @return routes represents by LinkedList of paths (ArrayLists) of path elements 
     * @throws RouteNotFoundException 
     */
    public LinkedList<ArrayList<PathElement>> getRoutes(
                    Protocol protocol, String srcIp, 
                    String destIp, int srcPort, 
                    int destPort, Network network) throws RouteNotFoundException, UnknownHostException {
        return getRoutes(protocol, (Inet4Address) Inet4Address.getByName(srcIp), (Inet4Address) Inet4Address.getByName(destIp), srcPort, destPort, network);
    }
    
    /** 
     * Getter
     * @return a description of this route provider
     */
    public abstract String getDescription();
}
